1 package org.apache.lucene.geo3d;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import java.util.ArrayList;
21 import java.util.BitSet;
22 import java.util.List;
23
24
25
26
27
28
29
30
31
32 public class GeoConvexPolygon extends GeoBasePolygon {
33
34 protected final List<GeoPoint> points;
35
36 protected final BitSet isInternalEdges;
37
38
39 protected SidedPlane[] edges = null;
40
41 protected GeoPoint[][] notableEdgePoints = null;
42
43 protected GeoPoint[] edgePoints = null;
44
45 protected double fullDistance = 0.0;
46
47 protected boolean isDone = false;
48
49
50
51
52
53
54
55 public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
56 super(planetModel);
57 this.points = pointList;
58 this.isInternalEdges = new BitSet();
59 done(false);
60 }
61
62
63
64
65
66
67
68
69
70 public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
71 final boolean returnEdgeInternal) {
72 super(planetModel);
73 this.points = pointList;
74 this.isInternalEdges = internalEdgeFlags;
75 done(returnEdgeInternal);
76 }
77
78
79
80
81
82
83
84
85 public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
86 super(planetModel);
87 points = new ArrayList<>();
88 isInternalEdges = new BitSet();
89 points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
90 }
91
92
93
94
95
96
97
98
99
100
101 public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
102 if (isDone)
103 throw new IllegalStateException("Can't call addPoint() if done() already called");
104 if (isInternalEdge)
105 isInternalEdges.set(points.size() - 1);
106 points.add(new GeoPoint(planetModel, latitude, longitude));
107 }
108
109
110
111
112
113 public void done(final boolean isInternalReturnEdge) {
114 if (isDone)
115 throw new IllegalStateException("Can't call done() more than once");
116
117 if (points.size() < 3)
118 throw new IllegalArgumentException("Polygon needs at least three points.");
119
120 if (isInternalReturnEdge)
121 isInternalEdges.set(points.size() - 1);
122
123 isDone = true;
124
125
126
127 edges = new SidedPlane[points.size()];
128 notableEdgePoints = new GeoPoint[points.size()][];
129
130 for (int i = 0; i < points.size(); i++) {
131 final GeoPoint start = points.get(i);
132 final GeoPoint end = points.get(legalIndex(i + 1));
133 final double distance = start.arcDistance(end);
134 if (distance > fullDistance)
135 fullDistance = distance;
136 final GeoPoint check = points.get(legalIndex(i + 2));
137 final SidedPlane sp = new SidedPlane(check, start, end);
138
139 edges[i] = sp;
140 notableEdgePoints[i] = new GeoPoint[]{start, end};
141 }
142 createCenterPoint();
143 }
144
145
146
147 protected void createCenterPoint() {
148
149
150
151
152 for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
153 final SidedPlane edge = edges[edgeIndex];
154 for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
155 if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
156 if (!edge.isWithin(points.get(pointIndex)))
157 throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
158 }
159 }
160 }
161 edgePoints = new GeoPoint[]{points.get(0)};
162 }
163
164
165
166
167
168 protected int legalIndex(int index) {
169 while (index >= points.size())
170 index -= points.size();
171 return index;
172 }
173
174 @Override
175 public boolean isWithin(final double x, final double y, final double z) {
176 for (final SidedPlane edge : edges) {
177 if (!edge.isWithin(x, y, z))
178 return false;
179 }
180 return true;
181 }
182
183 @Override
184 public GeoPoint[] getEdgePoints() {
185 return edgePoints;
186 }
187
188 @Override
189 public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
190
191 for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
192 final SidedPlane edge = edges[edgeIndex];
193 final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
194 if (!isInternalEdges.get(edgeIndex)) {
195
196
197
198 final Membership[] membershipBounds = new Membership[edges.length - 1];
199 int count = 0;
200 for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
201 if (otherIndex != edgeIndex) {
202 membershipBounds[count++] = edges[otherIndex];
203 }
204 }
205 if (edge.intersects(planetModel, p, notablePoints, points, bounds, membershipBounds)) {
206
207 return true;
208 }
209 }
210 }
211
212 return false;
213 }
214
215 @Override
216 public void getBounds(Bounds bounds) {
217 super.getBounds(bounds);
218
219
220 for (final GeoPoint point : points) {
221 bounds.addPoint(point);
222 }
223
224
225 for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
226 final SidedPlane edge = edges[edgeIndex];
227
228 final Membership[] membershipBounds = new Membership[edges.length - 1];
229 int count = 0;
230 for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
231 if (otherIndex != edgeIndex) {
232 membershipBounds[count++] = edges[otherIndex];
233 }
234 }
235 bounds.addPlane(planetModel, edge, membershipBounds);
236 }
237 }
238
239 @Override
240 protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
241 double minimumDistance = Double.MAX_VALUE;
242 for (final GeoPoint edgePoint : points) {
243 final double newDist = distanceStyle.computeDistance(edgePoint, x,y,z);
244 if (newDist < minimumDistance) {
245 minimumDistance = newDist;
246 }
247 }
248 for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
249 final Plane edgePlane = edges[edgeIndex];
250 final Membership[] membershipBounds = new Membership[edges.length - 1];
251 int count = 0;
252 for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
253 if (otherIndex != edgeIndex) {
254 membershipBounds[count++] = edges[otherIndex];
255 }
256 }
257 final double newDist = distanceStyle.computeDistance(planetModel, edgePlane, x, y, z, membershipBounds);
258 if (newDist < minimumDistance) {
259 minimumDistance = newDist;
260 }
261 }
262 return minimumDistance;
263 }
264
265 @Override
266 public boolean equals(Object o) {
267 if (!(o instanceof GeoConvexPolygon))
268 return false;
269 GeoConvexPolygon other = (GeoConvexPolygon) o;
270 if (!super.equals(other))
271 return false;
272 if (!other.isInternalEdges.equals(isInternalEdges))
273 return false;
274 return (other.points.equals(points));
275 }
276
277 @Override
278 public int hashCode() {
279 int result = super.hashCode();
280 result = 31 * result + points.hashCode();
281 return result;
282 }
283
284 @Override
285 public String toString() {
286 return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
287 }
288 }
289